package com.whut.service.impl;

import com.whut.enums.ProjectCheckEnum;
import com.whut.enums.ProjectSampleItemType;
import com.whut.enums.ProjectSampleState;
import com.whut.enums.ProjectSampleType;
import com.whut.mapper.*;
import com.whut.model.*;
import com.whut.service.ProjectSampleService;
import com.whut.v_bo.ProjectSampleItemSearch;
import com.whut.v_bo.ProjectSampleV1BO;
import com.whut.v_bo.ProjectSampleV2BO;
import com.whut.v_request.*;
import com.whut.v_vo.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

@Service
public class ProjectSampleServiceImpl implements ProjectSampleService {
    Logger POOL_LOG = LoggerFactory.getLogger("ProjectSample-Pool");
    Logger log = LoggerFactory.getLogger(ProjectSampleServiceImpl.class);

    @Resource
    private ProjectMapper projectMapper;

    @Resource
    private ProjectBuildMapper projectBuildMapper;

    @Resource
    private ProjectBuildCheckMapper projectBuildCheckMapper;

    @Resource
    private ProjectCheckMapper projectCheckMapper;

    @Resource
    private ProjectSampleMapper projectSampleMapper;

    @Resource
    private ProjectSampleItemMapper projectSampleItemMapper;

    private final Map<Integer, ProjectSampleV1Request> newRequestV1Map = new ConcurrentHashMap<>();

    private final Map<Integer, ProjectSampleV2Request> newRequestV2Map = new ConcurrentHashMap<>();

    /**
     * 质量隐患——开始抽样（楼栋抽样结果）
     * 1.楼栋数量为空时，此时选取总楼层数量；
     * 2.楼栋数量不为空，此时选取的楼层数量为每栋应抽取的楼层数量
     * ps: 抽样结果为一个可以抽样的最快速率层 + 加n个符合条件的随机层
     *
     * @param request
     * @return
     */
    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public ProjectSampleV1Response v1New(ProjectSampleV1Request request) {

        //项目ID
        Integer projectId = request.getProjectId();
        Project project = Optional.ofNullable(projectMapper.findById(projectId))
                .orElseThrow(() -> new IllegalArgumentException("项目不存在"));

        // 总结果
        List<ProjectSampleItem> newItems;
        //楼栋数量
        Integer buildNum = request.getBuildNum();
        //楼层数量
        Integer floorNum = request.getFloorNum();

        //根据选择的楼栋数量给给最终的List设置固定长度
        if (Objects.nonNull(buildNum)) {
            if (Objects.isNull(floorNum)) {
                floorNum = 2;  //选择楼栋为选择楼层数量时，默认每栋两层
                request.setFloorNum(floorNum);
            }
            newItems = new ArrayList<>(Math.min(buildNum - 1, 1) * floorNum);
        } else {
            newItems = new ArrayList<>();  //此时还不能确定有几栋
        }

        // pools
        List<ProjectSampleV1BO> pools = getProjectV1Pools(projectId);

        //先添加父级抽样结果数据
        ProjectSample sample = new ProjectSample();
        sample.setProjectId(projectId);
        sample.setType(ProjectSampleType.V1);
        sample.setName(String.format("%s-%s-%s", project.getId(), ProjectSampleType.V1.name(), LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))));
        sample.setState(ProjectSampleState.Created);
        projectSampleMapper.insert(sample);

        //记录请求的数据
        newRequestV1Map.put(sample.getId(), request);

        //选取楼栋数量不为空时
        if (Objects.nonNull(buildNum)) {

            // 按照 可抽样最快进度+可抽样个数 倒序排序 获取需要的栋数
            List<ProjectSampleV1BO> sortPools = pools.stream()
                    .filter(build -> build.isAvailable() && build.getAvailableSpeed() > 0)  //先过滤所有可抽取的楼栋
                    .sorted(    //根据楼栋可以抽样的整体速率进行倒排序
                            Comparator.comparingDouble(ProjectSampleV1BO::getAvailableSpeed).reversed().thenComparingInt(ProjectSampleV1BO::getLastNum)
                    ).collect(Collectors.toList());

            if (!sortPools.isEmpty()) {

                /**
                 * 筛选后数量不足时，随机抽取
                 */
                if (sortPools.size() < buildNum) {

                    List<ProjectSampleV1BO> randomPool = new ArrayList<>();

                    Collections.shuffle(pools);
                    pools.stream().forEach(unablePool -> {
                        sortPools.stream().forEach(sortPool -> {
                            if ((randomPool.size() + sortPools.size()) < buildNum) {
                                if (!unablePool.buildEquals(sortPool)) {
                                    randomPool.add(unablePool);
                                }
                            }
                        });
                    });
                    sortPools.addAll(randomPool);
                }

                //最终的list返回长度即为选择的楼栋数量
                List<ProjectSampleV1BO> subList = sortPools.subList(0, Math.min(buildNum, sortPools.size()));
                subList.stream().forEach(projectSampleV1BO -> {
                    ProjectSampleItem projectSampleItem = newProjectItemV1(null, ProjectSampleItemType.BUILD, projectSampleV1BO.getBuild(), null, null);
                    newItems.add(projectSampleItem);
                });
            }

            List<ProjectSampleItem> items = newItems.stream()
                    .map(ProjectSampleItem::getBuild)
                    .distinct()
                    .collect(Collectors.toList())
                    .stream()
                    .map(build -> newProjectItemV1(sample.getId(), ProjectSampleItemType.BUILD, build, null, null))
                    .sorted(
                            Comparator.comparing(ProjectSampleItem::getType)
                                    .thenComparing(ProjectSampleItem::getBuild)
                                    .thenComparing(ProjectSampleItem::getFloor)
                                    .thenComparing(ProjectSampleItem::getFamily)
                    )
                    .collect(Collectors.toList());

            if (items.size() > 0) {
                projectSampleItemMapper.insertBatch(items);
            }

        } else if (Objects.isNull(buildNum)) {  //选取楼栋数量为空

            Optional.ofNullable(floorNum).orElseThrow(() -> new IllegalArgumentException("非法的请求。"));

            if (Objects.nonNull(floorNum)) {

                //选取总层数
                List<ProjectSampleV1BO> floorPool = new ArrayList<>();
                for (ProjectSampleV1BO pool : pools) {
                    floorPool.addAll(pool.getChildren());
                }
                if (floorPool.size() > 0) {

                    //过滤所有无法抽样的楼层
                    //并根据所有楼层可以抽样的速率进行倒排序
                    List<ProjectSampleV1BO> sortFloorPools = floorPool.stream()
                            .filter(floor -> floor.isAvailable() && floor.getAvailableSpeed() > 0)
                            .sorted(Comparator.comparingDouble(ProjectSampleV1BO::getAvailableSpeed).reversed().thenComparingInt(ProjectSampleV1BO::getLastNum))
                            .collect(Collectors.toList());

                    /**
                     * 筛选后数量不足时，随机抽取
                     */
                    if (sortFloorPools.size() < floorNum) {
                        List<ProjectSampleV1BO> randomPool = new ArrayList<>();

                        Collections.shuffle(floorPool);
                        floorPool.stream().forEach(unablePool -> {
                            sortFloorPools.stream().forEach(sortPool -> {
                                if ((randomPool.size() + sortFloorPools.size()) < buildNum) {
                                    if (!unablePool.buildEquals(sortFloorPools)) {
                                        randomPool.add(unablePool);
                                    }
                                }
                            });
                        });
                        sortFloorPools.addAll(randomPool);
                    }

                    //从符合条件是数据中取出 一条速率最快 + n条符合条件的随机数据
                    List<ProjectSampleItem> randomSampleItem = getRandomSampleItem(sortFloorPools, newItems, Math.min(floorNum, sortFloorPools.size()), sample.getId());

                    //插入抽样结果子集
                    if (randomSampleItem.size() > 0) {
                        projectSampleItemMapper.insertBatch(randomSampleItem);
                    }
                }
            } else {
                //TODO 此时页面两个参数都没传递，理论上不应出现
            }
        }
        ProjectSample projectSample = projectSampleMapper.getById(sample.getId());
        return Optional.of(projectSample)
                .flatMap(t -> convertV1(t.getId()))
                .orElseThrow(() -> new RuntimeException("未知异常"));

    }

    /**
     * 质量隐患——确认抽样（标准层抽样结果）
     *
     * @param request
     * @return
     */
    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public ProjectSampleV1Response v1Step1Confirm(ProjectSampleV1Step1ConfirmRequest request) {
        ProjectSample sample = Optional.ofNullable(projectSampleMapper.getById(request.getSampleId()))
                .orElseThrow(() -> new IllegalArgumentException("抽样不存在"));
        Assert.isTrue(!ProjectSampleState.Created.equals(sample.getState()), "状态不合法");

        if (request.getModels() != null && !request.getModels().isEmpty()) {
            List<ProjectSampleItem> modifyItems = request.getModels().stream()
                    .map(build -> newProjectItemV1(request.getSampleId(), ProjectSampleItemType.BUILD, build.getId(), null, null))
                    .collect(Collectors.toList());
            projectSampleItemMapper.deleteBySampleId(request.getSampleId());
            projectSampleItemMapper.insertBatch(modifyItems);
        }
        ProjectSampleItemSearch search1 = new ProjectSampleItemSearch();
        search1.setSampleId(request.getSampleId());
        search1.setType(ProjectSampleItemType.BUILD);
        List<String> buildIds = projectSampleItemMapper.listBySearch(search1)
                .stream()
                .map(ProjectSampleItem::getBuild)
                .distinct()
                .collect(Collectors.toList());

        ProjectSampleV1Request v1Request = newRequestV1Map.getOrDefault(sample.getId(), new ProjectSampleV1Request());
        AtomicInteger buildNum = new AtomicInteger(v1Request.getBuildNum());
        Integer floorNum = v1Request.getFloorNum();

        List<ProjectSampleItem> newItems = new ArrayList<>();
        List<ProjectSampleV1BO> pools = getProjectV1Pools(sample.getProjectId());

        List<ProjectSampleV1BO> buildPools = pools.stream()
                .filter(t -> t.isAvailable() && t.getAvailableSpeed() > 0 && buildIds.contains(t.getBuild()))
                .collect(Collectors.toList());

        /**
         * 如果过滤后数量不足
         */
        if (buildPools.size() < request.getModels().size()) {
            buildPools = pools.stream()
                    .filter(t -> buildIds.contains(t.getBuild()))
                    .collect(Collectors.toList());
        }

        int otherBuildNum = Math.min(buildPools.size(), (Math.min(buildNum.get(), buildPools.size())));
        if (!buildPools.isEmpty()) {
            buildPools = buildPools.subList(0, otherBuildNum);
            Collections.shuffle(buildPools);
            buildNum.set(buildNum.get() - otherBuildNum);
        }
        for (ProjectSampleV1BO build : buildPools) {
            final int[] temp = {floorNum};
            List<ProjectSampleItem> newFloorItems = new ArrayList<>(temp[0]);
            // 最快层
            List<ProjectSampleItem> fastFloorItems = new ArrayList<>();
            // 最快抽样池
            List<ProjectSampleItem> fastFloorItemsPools = new ArrayList<>();
            build.getChildren().stream()
                    .filter(floor -> floor.isAvailable() && floor.getAvailableSpeed() > 0) //可以抽样的速率
                    .max(Comparator.comparingDouble(ProjectSampleV1BO::getAvailableSpeed))
                    .map(ProjectSampleV1BO::getAvailableSpeed)
                    .ifPresent(speed -> {
                        List<ProjectSampleV1BO> fastFloors = build.getChildren().stream()
                                .filter(floor -> floor.isAvailable() && speed.equals(floor.getAvailableSpeed()))
                                .collect(Collectors.toList());
                        if (!fastFloors.isEmpty()) {

                            Collections.shuffle(fastFloors);
                            ProjectSampleV1BO fastFloor = fastFloors.get(0);
                            fastFloorItemsPools.addAll(
                                    fastFloors.stream()
                                            .map(floor -> newProjectItemV1(sample.getId(), ProjectSampleItemType.FLOOR, floor.getBuild(), floor.getFloor(), null))
                                            .collect(Collectors.toList())
                            );
                            fastFloorItems.add(newProjectItemV1(sample.getId(), ProjectSampleItemType.FLOOR, fastFloor.getBuild(), fastFloor.getFloor(), null));
                            temp[0] = temp[0] - 1;
                        }
                    });

            // 其他层数 抽样
            Set<Integer> fastPoolFloorIds = fastFloorItemsPools.stream().map(ProjectSampleItem::getFloor).collect(Collectors.toSet());
            List<ProjectSampleV1BO> floors = build.getChildren().stream()
                    .filter(floor -> floor.isAvailable() && floor.getAvailableSpeed() > 0 && !fastPoolFloorIds.contains(floor.getFloor()))
                    .sorted(
                            Comparator.comparing(ProjectSampleV1BO::getAvailableSpeed).reversed()
                    )
                    .collect(Collectors.toList());

            if (temp[0] <= floors.size()) {
                // 剩余抽样层数 <= 其它层数
                newFloorItems.addAll(
                        floors.subList(0, temp[0])
                                .stream()
                                .map(floor -> newProjectItemV1(sample.getId(), ProjectSampleItemType.FLOOR, floor.getBuild(), floor.getFloor(), null))
                                .collect(Collectors.toList())
                );
                temp[0] = 0;
            } else if (temp[0] <= floors.size() + fastFloorItemsPools.size() - 1) {
                // 剩余抽样 <= 其他层数+最快层数
                newFloorItems.addAll(
                        floors.stream()
                                .map(floor -> newProjectItemV1(sample.getId(), ProjectSampleItemType.FLOOR, floor.getBuild(), floor.getFloor(), null))
                                .collect(Collectors.toList())
                );
                temp[0] -= floors.size();
                Set<Integer> fastFloorIds = fastFloorItems.stream().map(ProjectSampleItem::getFloor).collect(Collectors.toSet());
                List<ProjectSampleItem> otherItems = fastFloorItemsPools.stream()
                        .filter(item -> !fastFloorIds.contains(item.getFloor()))
                        .collect(Collectors.toList());
                newFloorItems.addAll(otherItems.subList(0, temp[0]));
                temp[0] = 0;
            } else {
                // 剩余抽样
                newFloorItems.addAll(
                        floors.stream()
                                .map(floor -> newProjectItemV1(sample.getId(), ProjectSampleItemType.FLOOR, floor.getBuild(), floor.getFloor(), null))
                                .collect(Collectors.toList())
                );
                Set<Integer> fastFloorIds = fastFloorItems.stream().map(ProjectSampleItem::getFloor).collect(Collectors.toSet());
                List<ProjectSampleItem> otherItems = fastFloorItemsPools.stream()
                        .filter(item -> !fastFloorIds.contains(item.getFloor()))
                        .collect(Collectors.toList());
                newFloorItems.addAll(otherItems);
                temp[0] = temp[0] - floors.size() - otherItems.size();
            }

            // 最后的倔犟-1
            if (temp[0] > 0) {
                Set<Integer> floor2Ids = newFloorItems.stream().map(ProjectSampleItem::getFloor).collect(Collectors.toSet());
                List<ProjectSampleV1BO> otherFloorPools = build.getChildren().stream()
                        .filter(floor -> !floor2Ids.contains(floor.getFloor()))
                        .sorted(
                                Comparator.comparing(ProjectSampleV1BO::isAvailable)
                                        .thenComparingDouble(ProjectSampleV1BO::getSpeed).reversed()
                        )
                        .collect(Collectors.toList());
                int size = Math.min(otherFloorPools.size(), temp[0]);
                Set<Double> speed = otherFloorPools.stream()
                        .limit(Math.min(otherFloorPools.size(), temp[0]))
                        .map(ProjectSampleV1BO::getSpeed)
                        .collect(Collectors.toSet());
                List<ProjectSampleV1BO> speedFloors = otherFloorPools.stream().filter(floor -> speed.contains(floor.getSpeed()))
                        .collect(Collectors.toList());
                Collections.shuffle(speedFloors);

                newFloorItems.addAll(
                        speedFloors.subList(0, size)
                                .stream()
                                .map(floor -> newProjectItemV1(sample.getId(), ProjectSampleItemType.FLOOR, floor.getBuild(), floor.getFloor(), null))
                                .collect(Collectors.toList())
                );
                temp[0] = temp[0] - size;
            }

            // 最后的倔犟-2
            if (temp[0] > 0) {
                Set<Integer> floor2Ids = newFloorItems.stream().map(ProjectSampleItem::getFloor).collect(Collectors.toSet());
                List<ProjectSampleV1BO> otherFloors = build.getChildren().stream()
                        .filter(floor -> !floor2Ids.contains(floor.getFloor()))
                        .sorted(
                                Comparator.comparing(ProjectSampleV1BO::isAvailable)
                                        .thenComparingDouble(ProjectSampleV1BO::getAvailableSpeed).reversed()
                        )
                        .collect(Collectors.toList());
                int num = Math.min(otherFloors.size(), temp[0]);
                newFloorItems.addAll(
                        otherFloors.subList(0, num)
                                .stream()
                                .map(floor -> newProjectItemV1(sample.getId(), ProjectSampleItemType.FLOOR, floor.getBuild(), floor.getFloor(), null))
                                .collect(Collectors.toList())
                );
            }
            newFloorItems.addAll(fastFloorItems);
            newItems.addAll(newFloorItems);
        }

        newItems.sort(Comparator.comparing(ProjectSampleItem::getType)
                .thenComparing(ProjectSampleItem::getBuild)
                .thenComparing(ProjectSampleItem::getFloor));
        projectSampleItemMapper.deleteBySampleId(request.getSampleId());
        if (!newItems.isEmpty()) {
            projectSampleItemMapper.insertBatch(newItems);
        }
        return Optional.of(projectSampleMapper.getById(sample.getId()))
                .flatMap(t -> convertV1(t.getId()))
                .orElseThrow(() -> new RuntimeException("未知异常"));
    }

    /**
     * 保存质量隐患抽样结果信息
     *
     * @param request
     * @return
     */
    @Override
    public ProjectSampleV1Response v1Step2Confirm(ProjectSampleV1Step2ConfirmRequest request) {
        ProjectSample sample = Optional.ofNullable(projectSampleMapper.getById(request.getSampleId()))
                .orElseThrow(() -> new IllegalArgumentException("抽样不存在"));
        Assert.isTrue(!ProjectSampleState.Created.equals(sample.getState()), "状态不合法");

        if (request.getModels() != null && !request.getModels().isEmpty()) {
            List<ProjectSampleItem> modifyItems = new ArrayList<>();
            request.getModels().forEach(build -> {
                if (build.getFloors() != null && !build.getFloors().isEmpty()) {
                    build.getFloors().forEach(floor -> modifyItems.add(newProjectItemV1(request.getSampleId(), ProjectSampleItemType.FLOOR, build.getId(), floor.getId(), null)));
                }
            });

            if (!modifyItems.isEmpty()) {
                projectSampleItemMapper.deleteBySampleId(request.getSampleId());
                projectSampleItemMapper.insertBatch(modifyItems);
            }
        }

        ProjectSample modifySample = new ProjectSample();
        modifySample.setId(sample.getId());
        modifySample.setState(ProjectSampleState.Confirm);
        modifySample.setRemark1(Optional.ofNullable(request.getRemark()).orElse(""));
        projectSampleMapper.updateById(modifySample);

        return Optional.of(projectSampleMapper.getById(sample.getId()))
                .flatMap(t -> convertV1(t.getId()))
                .orElseThrow(() -> new RuntimeException("未知异常"));
    }

    @Override
    public ProjectSampleV2Response v2New2(ProjectSampleV2Request request) {
        Integer projectId = request.getProjectId();
        Project project = Optional.ofNullable(projectMapper.findById(projectId))
                .orElseThrow(() -> new IllegalArgumentException("项目不存在"));

        //获取所有检查项
        List<ProjectCheck> checks = projectCheckMapper.findAll();

        List<ProjectSampleItem> newItems = new ArrayList<>();

        //遍历当前选择的检查项
        request.getChecks().forEach(requestCheck -> {
            Integer currentCheckId = requestCheck.getId();

            Integer checkId = requestCheck.getId();
            int num = requestCheck.getNum();

            List<Integer> trueChecks = new ArrayList<>();
            List<Integer> falseChecks = new ArrayList<>();
            if (currentCheckId.equals(ProjectCheckEnum.V1_1.INDEX) || currentCheckId.equals(ProjectCheckEnum.V1_2.INDEX)) {
                // 混凝土结构-拆模工程 || 砌筑工程
                trueChecks.add(currentCheckId);
                falseChecks.add(ProjectCheckEnum.V2.INDEX);
                falseChecks.add(ProjectCheckEnum.V4.INDEX);
            } else if (currentCheckId.equals(ProjectCheckEnum.V2.INDEX)) {
                // 建筑装饰-抹灰工程
                trueChecks.add(ProjectCheckEnum.V1_1.INDEX);
                trueChecks.add(ProjectCheckEnum.V1_2.INDEX);
                trueChecks.add(ProjectCheckEnum.V2.INDEX);
                falseChecks.add(ProjectCheckEnum.V4.INDEX);
            } else if (currentCheckId.equals(ProjectCheckEnum.V3_1.INDEX)
                    || currentCheckId.equals(ProjectCheckEnum.V3_2.INDEX)
                    || currentCheckId.equals(ProjectCheckEnum.V3_3.INDEX)
                    || currentCheckId.equals(ProjectCheckEnum.V3_4.INDEX)) {
                // 建筑装饰-门窗工程 || 建筑装饰-防水工程 || 建筑装饰-幕墙工程 || 钢结构
                trueChecks.add(currentCheckId);
            } else if (currentCheckId.equals(ProjectCheckEnum.V4.INDEX)) {
                // 精装修
                trueChecks.add(ProjectCheckEnum.V4.INDEX);
                trueChecks.add(ProjectCheckEnum.V2.INDEX);
                trueChecks.add(ProjectCheckEnum.V1_2.INDEX);
                trueChecks.add(ProjectCheckEnum.V1_1.INDEX);
            }

            //在抽样池中过滤实测实量抽样数据
            List<ProjectSampleV2BO> pools = getProjectV2Pools(projectId);

            List<ProjectSampleV2BO> floorPools = pools.stream()
                    .flatMap(buildPool -> buildPool.getChildren().stream())
                    .filter(t -> {   //过滤已经抽样的检查项
                        ProjectSampleV2BO.Check check = t.getChecks().stream()
                                .filter(ProjectSampleV2BO.Check::isAvailable)
                                .filter(ct -> checkId.equals(ct.getId()))
                                .findFirst()
                                .orElseGet(() -> {
                                    ProjectSampleV2BO.Check temp = new ProjectSampleV2BO.Check();
                                    temp.setId(checkId);
                                    temp.setOk(false);
                                    temp.setAvailable(true);
                                    return temp;
                                });
                        boolean trueCheck = trueChecks.stream()
                                .map(cid ->
                                        t.getChecks().stream()  //过滤当前层已经的检查项之前的检查项必须都完成，之后的检查项必须都未开始
                                                .filter(t1 -> t1.getId().equals(cid))
                                                .findFirst()
                                                .orElseGet(() -> {
                                                    ProjectSampleV2BO.Check defaultCheck = new ProjectSampleV2BO.Check();
                                                    defaultCheck.setId(cid);
                                                    defaultCheck.setOk(false);
                                                    defaultCheck.setAvailable(true);
                                                    return defaultCheck;
                                                })
                                ).allMatch(ProjectSampleV2BO.Check::isOk);
                        boolean falseCheck = falseChecks.stream()
                                .map(cid ->
                                        t.getChecks().stream()
                                                .filter(t1 -> t1.getId().equals(cid))
                                                .findFirst()
                                                .orElseGet(() -> {
                                                    ProjectSampleV2BO.Check defaultCheck = new ProjectSampleV2BO.Check();
                                                    defaultCheck.setId(cid);
                                                    defaultCheck.setOk(true);
                                                    defaultCheck.setAvailable(true);
                                                    return defaultCheck;
                                                })
                                ).noneMatch(ProjectSampleV2BO.Check::isOk);
                        return check.isOk() && check.isAvailable() && trueCheck && falseCheck;
                    }).collect(Collectors.toList());

            switch (requestCheck.getType()) {
                case BUILD:
                    List<ProjectSampleV2BO> buildPools = floorPools.stream()
                            .map(ProjectSampleV2BO::getParent)
                            .distinct()
                            .collect(Collectors.toList());
                    if (!buildPools.isEmpty()) {
                        Collections.shuffle(buildPools);
                        List<ProjectSampleItem> items = buildPools.subList(0, Math.min(buildPools.size(), num)).stream()
                                .peek(build -> build.setAvailable(false))
                                .map(build -> newProjectItemV2(null, ProjectSampleItemType.BUILD, checkId, build.getBuild(), null, null))
                                .collect(Collectors.toList());
                        newItems.addAll(items);
                    }
                    break;
                case FLOOR:
                    if (!floorPools.isEmpty()) {
                        Collections.shuffle(floorPools);
                        List<ProjectSampleItem> items = floorPools.subList(0, Math.min(floorPools.size(), num)).stream()
                                .peek(floor -> floor.getChecks().stream().filter(check -> check.getId().equals(checkId)).findFirst().ifPresent(check -> check.setAvailable(false)))
                                .map(floor -> newProjectItemV2(null, ProjectSampleItemType.FLOOR, checkId, floor.getBuild(), floor.getFloor(), null))
                                .collect(Collectors.toList());
                        newItems.addAll(items);
                    }
                    break;
                case FAMILY:
                    List<ProjectSampleV2BO> familyPools = floorPools.stream()
                            .flatMap(pool -> pool.getChildren().stream())
                            .filter(family -> family.getChecks().stream().anyMatch(check -> check.getId().equals(checkId) && check.isAvailable()))
                            .distinct()
                            .collect(Collectors.toList());
                    if (!familyPools.isEmpty()) {
                        Collections.shuffle(familyPools);
                        List<ProjectSampleItem> items = familyPools.subList(0, Math.min(familyPools.size(), num)).stream()
                                .peek(family -> family.getChecks().stream().filter(check -> check.getId().equals(checkId)).findFirst().ifPresent(check -> check.setAvailable(false)))
                                .map(family -> newProjectItemV2(null, ProjectSampleItemType.FAMILY, checkId, family.getBuild(), family.getFloor(), family.getFamily()))
                                .collect(Collectors.toList());
                        newItems.addAll(items);
                    }
                    break;
            }
        });

        ProjectSample sample = new ProjectSample();
        sample.setProjectId(projectId);
        sample.setType(ProjectSampleType.V2);
        sample.setName(String.format("%s-%s-%s", project.getId(), ProjectSampleType.V2.name(), LocalDateTime.now().

                format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))));
        sample.setState(ProjectSampleState.Created);

        projectSampleMapper.insert(sample);

        newItems.forEach(t -> t.setProjectSampleId(sample.getId()));
        newItems.sort(
                Comparator.comparing(ProjectSampleItem::getType)
                .thenComparing(ProjectSampleItem::getBuild)
                .thenComparing(ProjectSampleItem::getFloor)
        );
                // .thenComparing(ProjectSampleItem::getFamily));

        if (newItems.size() > 0) {
            projectSampleItemMapper.insertBatch(newItems);
        }

        newRequestV2Map.put(sample.getId(), request);
        return Optional.of(projectSampleMapper.getById(sample.getId()))
                .flatMap(t -> convertV2(t.getId()))
                .orElseThrow(() -> new RuntimeException("未知异常"));

    }

    @Override
    public ProjectSampleV2Response v2Confirm(ProjectSampleV2ConfirmRequest request) {

        ProjectSample sample = Optional.ofNullable(projectSampleMapper.getById(request.getSampleId()))
                .orElseThrow(() -> new IllegalArgumentException("抽样不存在"));
        Assert.isTrue(!ProjectSampleState.Created.equals(sample.getState()), "状态不合法");

        if (request.getCheckModels() != null && !request.getCheckModels().isEmpty()) {
            List<ProjectSampleItem> modifyItems = request.getCheckModels().stream()
                    .flatMap(checkModel -> checkModel.getModel().stream()
                            .map(model ->
                                    newProjectItemV2(
                                            request.getSampleId(),
                                            model.getType(),
                                            checkModel.getId(),
                                            model.getBuildId(),
                                            model.getFloorId(),
                                            model.getFamilyId()
                                    )
                            ))
                    .collect(Collectors.toList());
            projectSampleItemMapper.deleteBySampleId(request.getSampleId());
            projectSampleItemMapper.insertBatch(modifyItems);
        }

        ProjectSample modifySample = new ProjectSample();
        modifySample.setId(sample.getId());
        modifySample.setState(ProjectSampleState.Confirm);
        modifySample.setRemark1(Optional.ofNullable(request.getRemark()).orElse(""));
        projectSampleMapper.updateById(modifySample);

        return Optional.of(projectSampleMapper.getById(sample.getId()))
                .flatMap(t -> convertV2(t.getId()))
                .orElseThrow(() -> new RuntimeException("未知异常"));
    }

    @Override
    public ProjectSampleV1Response v1Get(Integer id) {
        return Optional.ofNullable(projectSampleMapper.getLast1(id, ProjectSampleType.V1))
                .flatMap(t -> convertV1(t.getId()))
                .orElseThrow(() -> new RuntimeException("未知异常"));
    }

    @Override
    public ProjectSampleV2Response v2Get(Integer id) {
        return Optional.ofNullable(projectSampleMapper.getLast1(id, ProjectSampleType.V2))
                .flatMap(t -> convertV2(t.getId()))
                .orElseThrow(() -> new RuntimeException("未知异常"));
    }

    @Override
    public ProjectSampleResponse get(Integer id) {
        ProjectSampleResponse response = new ProjectSampleResponse();

        //V1 质量隐患，抽样结果
        response.setV1(
                Optional.ofNullable(projectSampleMapper.getLast1(id, ProjectSampleType.V1))
                        .flatMap(t -> convertV1(t.getId()))
                        .orElse(null)
        );

        // V2 实测实量，抽样结果
        response.setV2(
                Optional.ofNullable(projectSampleMapper.getLast1(id, ProjectSampleType.V2))
                        .flatMap(t -> convertV2(t.getId()))
                        .orElse(null)
        );

        //V3 地下室抽样结果
        response.setV3(
                Optional.ofNullable(projectSampleMapper.getLast1(id, ProjectSampleType.V3))
                        .flatMap(t -> convertV3(t.getId()))
                        .orElse(null)
        );
        return response;
    }

    @Override
    public boolean isAvailable(ProjectSampleItemAvailableRequest request) {
        List<Integer> sampleIds = projectSampleMapper.listByProjectAndType(request.getProjectId(), request.getSampleType()).stream()
                .map(ProjectSample::getId).collect(Collectors.toList());
        if (sampleIds.isEmpty()) {
            return true;
        }
        List<ProjectSampleItem> items = new ArrayList<>();

        ProjectSampleItemSearch search = new ProjectSampleItemSearch();
        search.setSampleIds(sampleIds);
        if (request.getBuild() != null) {
            search.setType(ProjectSampleItemType.BUILD);
            search.setBuild(request.getBuild());
            items.addAll(projectSampleItemMapper.listBySearch(search));
            if (request.getFloor() != null) {
                search.setType(ProjectSampleItemType.FLOOR);
                search.setFloor(request.getFloor());
                items.addAll(projectSampleItemMapper.listBySearch(search));
                if (request.getFamily() != null) {
                    search.setType(ProjectSampleItemType.FAMILY);
                    search.setFloor(request.getFamily());
                    items.addAll(projectSampleItemMapper.listBySearch(search));
                }
            }
        }

        return items.isEmpty();
    }

    /**
     * 质量隐患——抽样池
     *
     * @param projectId
     * @return
     */
    private List<ProjectSampleV1BO> getProjectV1Pools(Integer projectId) {
        List<ProjectCheck> checks = projectCheckMapper.findAll();

        List<ProjectBuild> builds = projectBuildMapper.findByProjectId(projectId);
        List<ProjectBuildCheck> buildChecks = projectBuildCheckMapper.listByProjectId(projectId);

        List<ProjectSample> samples = projectSampleMapper.listByProjectAndType(projectId, ProjectSampleType.V1);
        ProjectSampleItemSearch itemSearch = new ProjectSampleItemSearch();
        itemSearch.setSampleIds(samples.stream().map(ProjectSample::getId).collect(Collectors.toList()));
        List<ProjectSampleItem> items = !itemSearch.getSampleIds().isEmpty() ? projectSampleItemMapper.listBySearch(itemSearch) : Collections.emptyList();

        List<ProjectSampleV1BO> pools = builds.stream()
                .map(build -> {
                    ProjectSampleV1BO buildBO = new ProjectSampleV1BO();
                    buildBO.setType(ProjectSampleItemType.BUILD);
                    buildBO.setBuild(build.getBuild());
                    buildBO.setAvailable(
                            items.stream()
                                    .filter(i -> ProjectSampleItemType.BUILD.equals(i.getType())
                                            && build.getBuild().equals(i.getBuild())
                                    )
                                    .noneMatch(t -> true)
                    );
                    List<ProjectSampleV1BO> floorBOs = IntStream.range(build.getStandardFloorNum() + 1, build.getFloorNum() + 1)
                            .mapToObj(floor -> {
                                List<ProjectSampleV1BO.Check> floorChecks = checks.stream()
                                        .map(c -> {
                                            boolean ok = buildChecks.stream()
                                                    .filter(bc -> build.getId().equals(bc.getProjectBuildId())
                                                            && c.getId().equals(bc.getProjectCheckId())
                                                            && bc.getFloor().equals(floor)
                                                    ).anyMatch(t -> true);
                                            ProjectSampleV1BO.Check check = new ProjectSampleV1BO.Check();
                                            check.setId(c.getId());
                                            check.setOk(ok);
                                            return check;
                                        })
                                        .collect(Collectors.toList());

                                ProjectSampleV1BO floorBO = new ProjectSampleV1BO();
                                floorBO.setType(ProjectSampleItemType.FLOOR);
                                floorBO.setFloor(floor);
                                floorBO.setChecks(floorChecks);
                                floorBO.setAvailable(
                                        items.stream()
                                                .filter(i -> ProjectSampleItemType.FLOOR.equals(i.getType())
                                                        && build.getBuild().equals(i.getBuild())
                                                        && Integer.valueOf(floor).equals(i.getFloor())
                                                )
                                                .noneMatch(t -> true)
                                );
                                floorBO.setParent(buildBO);

                                List<ProjectSampleV1BO> familyBOs = IntStream.range(1, build.getFamilyNum() + 1)
                                        .mapToObj(family -> {
                                            ProjectSampleV1BO familyBO = new ProjectSampleV1BO();
                                            familyBO.setType(ProjectSampleItemType.FAMILY);
                                            familyBO.setFamily(family);
                                            familyBO.setAvailable(
                                                    items.stream()
                                                            .filter(i -> ProjectSampleItemType.FAMILY.equals(i.getType())
                                                                    && build.getBuild().equals(i.getBuild())
                                                                    && Integer.valueOf(floor).equals(i.getFloor())
                                                                    && Integer.valueOf(family).equals(i.getFamily())
                                                            )
                                                            .noneMatch(t -> true)
                                            );
                                            familyBO.setParent(floorBO);
                                            return familyBO;
                                        })
                                        .collect(Collectors.toList());
                                floorBO.setChildren(familyBOs);

                                return floorBO;
                            })
                            .collect(Collectors.toList());
                    buildBO.setChildren(floorBOs);
                    return buildBO;
                })
                .collect(Collectors.toList());

        POOL_LOG.info(
                "Project[{}] V1 Pool Info [Size: {} Speed: {} availableSpeed: {}] ",
                projectId, pools.size(),
                BigDecimal.valueOf(pools.stream().mapToDouble(ProjectSampleV1BO::getSpeed).sum()).divide(BigDecimal.valueOf(pools.size()), 4, BigDecimal.ROUND_DOWN).doubleValue(),
                BigDecimal.valueOf(pools.stream().mapToDouble(ProjectSampleV1BO::getAvailableSpeed).sum()).divide(BigDecimal.valueOf(pools.size()), 4, BigDecimal.ROUND_DOWN).doubleValue()
        );
        pools.forEach(build -> {
            POOL_LOG.info("\tBuild: {} Speed: {} availableSpeed: {} LastNum : {} Ok: {}", build.getBuild(), build.getSpeed(), build.getAvailableSpeed(), build.getLastNum(), build.isAvailable());
            build.getChildren().forEach(floor -> {
                POOL_LOG.info("\t\tFloor: {} Speed: {} availableSpeed: {} LastNum : {} Ok: {} Check: [ok: {}, size: {}]", floor.getFloor(), floor.getSpeed(), floor.getAvailableSpeed(), floor.getLastNum(), floor.isAvailable(), floor.getChecks().stream().filter(ProjectSampleV1BO.Check::isOk).count(), floor.getChecks().size());
                floor.getChildren().forEach(family -> POOL_LOG.info("\t\t\tFamily: {} Speed: {} availableSpeed: {} LastNum : {} Ok: {},", family.getFamily(), family.getSpeed(), floor.getAvailableSpeed(), family.getLastNum(), family.isAvailable()));
            });
        });

        return pools;
    }

    /**
     * 实测实量——抽样池
     *
     * @param projectId
     * @return
     */
    private List<ProjectSampleV2BO> getProjectV2Pools(Integer projectId) {
        List<ProjectCheck> checks = projectCheckMapper.findAll(); //项目——检查项

        List<ProjectBuild> builds = projectBuildMapper.findByProjectId(projectId);  //获取项目下所有的楼栋
        List<ProjectBuildCheck> buildChecks = projectBuildCheckMapper.listByProjectId(projectId); // 项目——楼栋——检查项 （关联信息列表）

        //抽样池中的项目数据
        List<ProjectSample> samples = projectSampleMapper.listByProjectAndType(projectId, ProjectSampleType.V2);
        ProjectSampleItemSearch itemSearch = new ProjectSampleItemSearch();
        itemSearch.setSampleIds(samples.stream().map(ProjectSample::getId).collect(Collectors.toList()));

        //抽样池中的项目子集
        List<ProjectSampleItem> items = !itemSearch.getSampleIds().isEmpty() ? projectSampleItemMapper.listBySearch(itemSearch) : Collections.emptyList();

        //对项目下所有楼栋进行遍历
        List<ProjectSampleV2BO> pools = builds.stream()
                .map(build -> {

                    //先取楼栋信息
                    ProjectSampleV2BO buildBO = new ProjectSampleV2BO();
                    buildBO.setType(ProjectSampleItemType.BUILD);
                    buildBO.setBuild(build.getBuild());
                    buildBO.setAvailable(
                            items.stream()
                                    .filter(i -> ProjectSampleItemType.BUILD.equals(i.getType())
                                            && build.getBuild().equals(i.getBuild())
                                    )
                                    .noneMatch(t -> true)
                    );

                    //在赋值楼栋下的层信息
                    List<ProjectSampleV2BO> floorBOs = IntStream.range(build.getStandardFloorNum() + 1, build.getFloorNum() + 1)
                            .mapToObj(floor -> {
                                List<ProjectSampleV2BO.Check> floorChecks = checks.stream()
                                        .sorted(Comparator.comparing(ProjectCheck::getId))
                                        .map(c -> {

                                            //当前层是否完成
                                            boolean ok = buildChecks.stream()
                                                    .filter(bc -> c.getId().equals(bc.getProjectCheckId())
                                                            && build.getId().equals(bc.getProjectBuildId())
                                                            && bc.getFloor().equals(floor)
                                                    )
                                                    .anyMatch(t -> true);

                                            //是否可用（抽样过==flase 未抽样==true）
                                            boolean available = items.stream()
                                                    .noneMatch(item -> item.getType().equals(ProjectSampleItemType.FLOOR)
                                                            && c.getId().equals(item.getCheckId())
                                                            && item.getBuild().equals(build.getBuild())
                                                            && item.getFloor().equals(floor)
                                                    );
                                            ProjectSampleV2BO.Check check = new ProjectSampleV2BO.Check();
                                            check.setId(c.getId());
                                            check.setOk(ok);
                                            check.setAvailable(available);
                                            return check;
                                        }).collect(Collectors.toList());

                                ProjectSampleV2BO floorBO = new ProjectSampleV2BO();
                                floorBO.setType(ProjectSampleItemType.FLOOR);
                                floorBO.setFloor(floor);
                                floorBO.setChecks(floorChecks);
                                // floorBO.setAvailable(
                                //         items.stream()
                                //                 .filter(i -> ProjectSampleItemType.FLOOR.equals(i.getType())
                                //                         && build.getBuild().equals(i.getBuild())
                                //                         && Integer.valueOf(floor).equals(i.getFloor())
                                //                 )
                                //                 .noneMatch(t -> true)
                                // );
                                floorBO.setParent(buildBO);

                                //赋值层下面的户型信息project/build
                                List<ProjectSampleV2BO> familyBOs = IntStream.range(1, build.getFamilyNum() + 1)
                                        .mapToObj(family -> {
                                            List<ProjectSampleV2BO.Check> familyChecks = checks.stream()
                                                    .sorted(Comparator.comparing(ProjectCheck::getId))
                                                    .map(c -> {
                                                        boolean ok = buildChecks.stream()
                                                                .filter(bc -> c.getId().equals(bc.getProjectCheckId())
                                                                        && build.getId().equals(bc.getProjectBuildId())
                                                                        && bc.getFloor().equals(floor)
                                                                )
                                                                .anyMatch(t -> true);
                                                        boolean available = items.stream()
                                                                .noneMatch(item -> item.getType().equals(ProjectSampleItemType.FAMILY)
                                                                        && c.getId().equals(item.getCheckId())
                                                                        && item.getBuild().equals(build.getBuild())
                                                                        && item.getFloor().equals(floor)
                                                                        && item.getFamily().equals(family)
                                                                );
                                                        ProjectSampleV2BO.Check check = new ProjectSampleV2BO.Check();
                                                        check.setId(c.getId());
                                                        check.setOk(ok);
                                                        check.setAvailable(available);
                                                        return check;
                                                    }).collect(Collectors.toList());

                                            ProjectSampleV2BO familyBO = new ProjectSampleV2BO();
                                            familyBO.setType(ProjectSampleItemType.FAMILY);
                                            familyBO.setFamily(family);
                                            familyBO.setChecks(familyChecks);
                                            familyBO.setAvailable(
                                                    items.stream()
                                                            .filter(i -> ProjectSampleItemType.FAMILY.equals(i.getType())
                                                                    && build.getBuild().equals(i.getBuild())
                                                                    && Integer.valueOf(floor).equals(i.getFloor())
                                                                    && Integer.valueOf(family).equals(i.getFamily())
                                                            )
                                                            .noneMatch(t -> true)
                                            );

                                            familyBO.setParent(floorBO);
                                            return familyBO;
                                        })
                                        .collect(Collectors.toList());
                                floorBO.setChildren(familyBOs);

                                return floorBO;
                            })
                            .collect(Collectors.toList());
                    buildBO.setChildren(floorBOs);
                    return buildBO;
                })
                .collect(Collectors.toList());

        /*POOL_LOG.info(
                "Project[{}] V2 Pool Info [Size: {} Speed: {} NoOkSpeed: {}] ",
                projectId, pools.size(),
                BigDecimal.valueOf(pools.stream().mapToDouble(ProjectSampleV2BO::getSpeed).sum()).divide(BigDecimal.valueOf(pools.size()), 4, BigDecimal.ROUND_DOWN).doubleValue(),
                BigDecimal.valueOf(pools.stream().mapToDouble(ProjectSampleV2BO::getAvailableSpeed).sum()).divide(BigDecimal.valueOf(pools.size()), 4, BigDecimal.ROUND_DOWN).doubleValue()
        );
        pools.forEach(build -> {
            POOL_LOG.info("\tBuild: {} Speed: {} availableSpeed: {} LastNum : {} available: {}", build.getBuild(), build.getSpeed(), build.getAvailableSpeed(), build.getLastNum(), build.isAvailable());
            build.getChildren().forEach(floor -> {
                POOL_LOG.info("\t\tFloor: {} Speed: {} availableSpeed: {} LastNum : {} available: {} Check: [available: {}, size: {}]", floor.getFloor(), floor.getSpeed(), floor.getAvailableSpeed(), floor.getLastNum(), floor.isAvailable(), floor.getChecks().stream().filter(ProjectSampleV2BO.Check::isOk).count(), floor.getChecks().size());
                floor.getChecks().forEach(t -> POOL_LOG.info("\t\t\tFloorCheck-> Id: {} available: {} Ok: {}", t.getId(), t.isAvailable(), t.isOk()));
                floor.getChildren().forEach(family -> {
                    POOL_LOG.info("\t\t\t\tFamily: {} Speed: {} available: {} availableSpeed: {} LastNum: {}", family.getFamily(), family.getSpeed(), family.isAvailable(), floor.getAvailableSpeed(), family.getLastNum());
                    family.getChecks().forEach(check -> POOL_LOG.info("\t\t\t\t\tFamilyCheck: {} available: {} Ok: {}", check.getId(), check.isAvailable(), check.isOk()));
                });
            });
        });*/

        return pools;
    }

    private List<ProjectSampleV1Response.Build> convertBuildModels(Integer projectId, List<ProjectSampleItem> items) {
        Map<String, ProjectBuild> projectBuildMap = items.stream()
                .map(ProjectSampleItem::getBuild)
                .distinct()
                .map(build -> Optional.ofNullable(projectBuildMapper.findByProjectAndBuild(projectId, build)).orElse(defaultProjectBuild(projectId, build)))
                .collect(Collectors.toMap(ProjectBuild::getBuild, b -> b));


        return projectBuildMap.values().stream().sorted()
                .map(projectBuild -> {
                    List<ProjectSampleV1Response.Floor> floors = items.stream()
                            .filter(t -> projectBuild.getBuild().equals(t.getBuild()) && t.getFloor() != null)
                            .map(ProjectSampleItem::getFloor)
                            .map(floorItem -> {
                                List<ProjectSampleV1Response.Family> families = items.stream()
                                        .filter(t    -> projectBuild.getBuild().equals(t.getBuild()) && floorItem.equals(t.getFloor()) && t.getFamily() != null)
                                        .map(ProjectSampleItem::getFamily)
                                        .sorted()
                                        .map(familyItem -> {
                                            ProjectSampleV1Response.Family family = new ProjectSampleV1Response.Family();
                                            family.setId(familyItem);
                                            family.setName(familyItem.toString() + "户");
                                            return family;
                                        })
                                        .collect(Collectors.toList());
                                ProjectSampleV1Response.Floor floor = new ProjectSampleV1Response.Floor();
                                floor.setId(floorItem);
                                floor.setName(floorItem.toString() + "层");
                                floor.setFamilies(families);
                                return floor;
                            })
                            .sorted(Comparator.comparing(ProjectSampleV1Response.Floor::getId))
                            .collect(Collectors.toList());
                    ProjectSampleV1Response.Build build = new ProjectSampleV1Response.Build();
                    build.setId(projectBuild.getBuild());
                    build.setName(projectBuild.getBuild() + "楼栋");
                    build.setFloors(floors);
                    return build;
                })
                .sorted(Comparator.comparing(ProjectSampleV1Response.Build::getName))
                .collect(Collectors.toList());
    }

    private List<ProjectSampleV2Response.CheckItem> convertV2Models(Integer projectId, List<ProjectSampleItem> items) {
        List<ProjectCheck> checks = items.stream()
                .map(ProjectSampleItem::getCheckId)
                .distinct()
                .map(t -> Optional.ofNullable(projectCheckMapper.findById(t)).orElse(defaultProjectCheck(t)))
                .collect(Collectors.toList());

        Map<String, ProjectBuild> projectBuildMap = items.stream()
                .map(ProjectSampleItem::getBuild)
                .distinct()
                .map(build -> Optional.ofNullable(projectBuildMapper.findByProjectAndBuild(projectId, build)).orElse(defaultProjectBuild(projectId, build)))
                .collect(Collectors.toMap(ProjectBuild::getBuild, t -> t));

        return checks.stream()
                .sorted(Comparator.comparingLong(ProjectCheck::getSort))
                .map(check -> {
                    ProjectSampleV2Response.CheckItem checkItem = new ProjectSampleV2Response.CheckItem();
                    checkItem.setId(check.getId());
                    checkItem.setName(check.getName());
                    List<ProjectSampleItemModel> models = items.stream().filter(i -> check.getId().equals(i.getCheckId()))
                            .map(t -> {
                                ProjectSampleItemModel model = new ProjectSampleItemModel();
                                model.setId(t.getId());
                                model.setType(t.getType());
                                model.setBuildId(t.getBuild());
                                model.setBuild(projectBuildMap.getOrDefault(t.getBuild(), defaultProjectBuild(projectId, t.getBuild())).getBuild() + "楼栋");
                                model.setFloorId(t.getFloor());
                                model.setFloor(Optional.ofNullable(t.getFloor()).map(s -> s + "层").orElse(null));
                                model.setFamilyId(t.getFamily());
                                model.setFamily(Optional.ofNullable(t.getFamily()).map(s -> s + "户").orElse(null));
                                return model;
                            }).collect(Collectors.toList());
                    checkItem.setModel(models);
                    return checkItem;
                })

                .collect(Collectors.toList());
    }

    private Optional<ProjectSampleV1Response> convertV1(Integer sampleId) {
        return Optional.ofNullable(projectSampleMapper.getById(sampleId))
                .map(t -> {
                    ProjectSampleItemSearch param = new ProjectSampleItemSearch();
                    param.setSampleId(t.getId());
                    List<ProjectSampleItem> items = projectSampleItemMapper.listBySearch(param);
                    ProjectSampleV1Response response = new ProjectSampleV1Response();
                    response.setId(t.getId());
                    response.setName(t.getName());
                    response.setCreatedTime(t.getCreatedTime());
                    response.setModels(convertBuildModels(t.getProjectId(), items));
                    response.setRemark(t.getRemark1());
                    return response;
                });
    }

    private Optional<ProjectSampleV2Response> convertV2(Integer sampleId) {
        return Optional.ofNullable(projectSampleMapper.getById(sampleId))
                .map(t -> {
                    ProjectSampleItemSearch param = new ProjectSampleItemSearch();
                    param.setSampleId(t.getId());
                    List<ProjectSampleItem> items = projectSampleItemMapper.listBySearch(param);
                    ProjectSampleV2Response response = new ProjectSampleV2Response();
                    response.setId(t.getId());
                    response.setName(t.getName());
                    response.setCreatedTime(t.getCreatedTime());
                    response.setModels(convertV2Models(t.getProjectId(), items));
                    response.setRemark(t.getRemark1());
                    return response;
                });
    }

    private ProjectBuild defaultProjectBuild(Integer projectId, String build) {
        ProjectBuild t = new ProjectBuild();
        t.setProjectId(projectId);
        t.setBuild(build);
        return t;
    }

    private ProjectCheck defaultProjectCheck(Integer id) {
        ProjectCheck t = new ProjectCheck();
        t.setId(id);
        t.setName("已删除");
        return t;
    }

    private ProjectSampleItem newProjectItemV1(Integer sampleId, ProjectSampleItemType type, String build, Integer floor, Integer family) {
        ProjectSampleItem item = new ProjectSampleItem();
        item.setProjectSampleId(sampleId);
        item.setType(type);
        switch (type) {
            case FAMILY:
                item.setFamily(family);
            case FLOOR:
                item.setFloor(floor);
            case BUILD:
                item.setBuild(build);
        }
        return item;
    }

    private ProjectSampleItem newProjectItemV2(Integer sampleId, ProjectSampleItemType type, Integer checkId, String build, Integer floor, Integer family) {
        ProjectSampleItem item = new ProjectSampleItem();
        item.setProjectSampleId(sampleId);
        item.setType(type);
        item.setCheckId(checkId);
        switch (type) {
            case FAMILY:
                item.setFamily(family);
            case FLOOR:
                item.setFloor(floor);
            case BUILD:
                item.setBuild(build);
        }
        return item;
    }

    /**
     * 从所有符合条件的数据中取得一个最快速率的列表和n个随机数据 （楼层级别）
     *
     * @param sourceList 源数据（所有符合条件的楼层列表）
     * @param resultList 结果集 一个最快的 + countNum - 1 条随机数据
     * @param countNum   结果集数量
     * @return
     */
    private List<ProjectSampleItem> getRandomSampleItem(List<ProjectSampleV1BO> sourceList, List<ProjectSampleItem> resultList, Integer countNum, Integer sampleId) {

        //速率最快的数据
        ProjectSampleV1BO projectSampleV1FirstBO = sourceList.get(0);
        sourceList.remove(0);  //移除已经取出的数据

        ProjectSampleItem projectSampleItem = newProjectItemV1(sampleId, ProjectSampleItemType.FLOOR, projectSampleV1FirstBO.getBuild(), projectSampleV1FirstBO.getFloor(), null);
        resultList.add(projectSampleItem); //放入速率最快的数据

        //随机取出n条不重复的数据
        for (int i = countNum - 1; i >= 1; i--) {
            Random random = new Random();
            int j = random.nextInt(sourceList.size() - 1);
            ProjectSampleV1BO projectSampleV1RandomBO = sourceList.get(j);
            ProjectSampleItem projectSampleRandomItem = newProjectItemV1(sampleId, ProjectSampleItemType.FLOOR, projectSampleV1RandomBO.getBuild(), projectSampleV1RandomBO.getFloor(), null);
            resultList.add(projectSampleRandomItem);
            //把已取到的数据移除,避免下次再次取到出现重复
            sourceList.remove(j);

        }

        return resultList;

    }

    private Optional<ProjectSampleV3Response> convertV3(Integer sampleId) {
        return Optional.ofNullable(projectSampleMapper.getById(sampleId))
                .map(t -> {
                    ProjectSampleItemSearch param = new ProjectSampleItemSearch();
                    param.setSampleId(t.getId());
                    List<ProjectSampleItem> items = projectSampleItemMapper.listBySearch(param);
                    ProjectSampleV3Response response = new ProjectSampleV3Response();
                    response.setId(t.getId());
                    response.setName(t.getName());
                    response.setCreatedTime(t.getCreatedTime());
                    response.setModels(convertV3Models(items));
                    response.setRemark(t.getRemark1());
                    return response;
                });
    }

    private List<ProjectSampleV3Response.Build> convertV3Models(List<ProjectSampleItem> items) {

        List<ProjectSampleV3Response.Build> results = new ArrayList<>();

        items.stream().forEach(item -> {
            ProjectSampleV3Response.Build buildName = new ProjectSampleV3Response.Build();
            buildName.setId(item.getBuild());
            buildName.setName(item.getBuild() + "楼栋");
            results.add(buildName);

        });
        return results;
    }


    //public static void main(String[] args) {
    //    Stream.of(
    //            new A().setOk(false).setNum(0D),
    //            new A().setOk(false).setNum(0D),
    //            new A().setOk(true).setNum(0.1D),
    //            new A().setOk(true).setNum(0.3D),
    //            new A().setOk(true).setNum(0.2D)
    //    ).sorted(
    //            Comparator.comparing(A::getOk)
    //            .thenComparingDouble(A::getNum).reversed()
    //    ).peek(t-> System.out.println(t)).collect(Collectors.toList());
    //}
//
//
    //@Data
    //@Accessors(chain = true)
    //public static class A {
    //    private Boolean ok;
    //    private Double num;
    //}
}